#pragma once

#include <sys/time.h>
#include <strings.h>
#include <stdio.h>
#include <assert.h>
#include <stdarg.h>
#include <time.h>
#include "include/define_util.h"

static struct timeval start_tv, stop_tv;
static const char *OUTPUT_PREFIX = "[RTA] ";
#define MB	(1024. * 1024.)
#define KB	(1024.)

#include <fstream>
#include <cstdarg>
#include <cstdio>
#include <string>

class Logger {
public:
	static void init(const std::string& filename) {
		// 打开文件以写入模式，清空内容
		std::ofstream outfile(filename, std::ios::out);
		if (outfile.is_open()) {
			outfile.close();
		}
		else {
			printf("Failed to open file %s\n", filename.c_str());
		}
	}
    // 静态方法：将格式化内容写入文件末尾
    static void log(const std::string& filename, const char* format, ...) {
        // 构造可变参数列表
        va_list args;
        va_start(args, format);

        // 格式化字符串缓冲区
        char buffer[1024];
        vsnprintf(buffer, sizeof(buffer), format, args);

        va_end(args);

        // 打开文件以追加方式写入
        std::ofstream outfile(filename, std::ios::app);
        if (outfile.is_open()) {
            outfile << buffer;  // 不自动加换行
            // outfile << buffer << std::endl; // 如果你想自动换行，可以用这一行
            outfile.close();
        }
    }
};


/*
 * Print the output to the specified stream with a custom prefix.
 */
static void INFO(const char *format, ...) {
    va_list args;
    va_start(args, format);
    fprintf(stderr, "%s", OUTPUT_PREFIX);
    vfprintf(stderr, format, args);
    va_end(args);
}

/*
 * Make the time spend be usecs.
 */
static void settime(uint64 usecs){
	bzero((void*)&start_tv, sizeof(start_tv));
	stop_tv.tv_sec = usecs / 1000000;
	stop_tv.tv_usec = usecs % 1000000;
}

static void tvsub(struct timeval * tdiff, struct timeval * t1, struct timeval * t0){
	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
	if (tdiff->tv_usec < 0 && tdiff->tv_sec > 0) {
		tdiff->tv_sec--;
		tdiff->tv_usec += 1000000;
		assert(tdiff->tv_usec >= 0);
	}

	/* time shouldn't go backwards!!! */
	if (tdiff->tv_usec < 0 || t1->tv_sec < t0->tv_sec) {
		tdiff->tv_sec = 0;
		tdiff->tv_usec = 0;
	}
}

static uint64 tvdelta(struct timeval *start, struct timeval *stop){
	struct timeval td;
	uint64	usecs;

	tvsub(&td, stop, start);
	usecs = td.tv_sec;
	usecs *= 1000000;
	usecs += td.tv_usec;
	return (usecs);
}

/*
 * Start timing now.
 */
static void start(struct timeval *tv){
	if (tv == NULL)
		tv = &start_tv;

	(void) gettimeofday(tv, (struct timezone *) 0);
}

/*
 * Stop timing and return real time in microseconds.
 */
static uint64 stop(struct timeval *begin, struct timeval *end){
	if (end == NULL)
		end = &stop_tv;
	(void) gettimeofday(end, (struct timezone *) 0);

	if (begin == NULL)
		begin = &start_tv;

	return (tvdelta(begin, end));
}

static uint64 gettime(void){
    static struct timespec ts;
    static u64 receive_time_ns;

    // 获取当前时间（纳秒）
    clock_gettime(CLOCK_MONOTONIC, &ts);
    receive_time_ns = ts.tv_sec * 1000000000LL + ts.tv_nsec;
	return receive_time_ns / 1000;
}

/*
 * Return the time in usecs since the last settime call.
 */
static void calculate_bandwidth(uint64 time, uint64 bytes, uint64 iter){
	double secs = (double)time / 1000000.0;
	double mb;

	INFO("Time: %f seconds\n", secs);
    mb = bytes / MB;
	// if (mb < 1.)
	// 	(void) INFO("size: %.6f MB ", mb);
	// else
	// 	(void) INFO("size: %.2f MB ", mb);
	if (mb / secs < 1.)
		(void) INFO("bandwidth: %.6f MB/s\n", mb/secs);
	else
		(void) INFO("bandwidth: %.2f MB/s\n", mb/secs);
}